/*  ----------------------------------------------------------------------------
 *  Arello Mobile
 *  Fast 3d Engine
 *  ----------------------------------------------------------------------------
 * Except where otherwise noted, this work is licensed under
 * http://creativecommons.org/licenses/by/3.0
 */

#include "Manager.h"
#include "Listener.h"
#include <input/hard/Hardware.h>
#include <Atom.h>

namespace liba
{
namespace input
{

Manager::Queue * Manager::queue = 0;
Manager::Listeners * Manager::listeners = 0;
threads::Mutex Manager::mutex;

const Atom Manager::strange_type_name("Strange");
const Atom Manager::mouse_type_name("Mouse");
const Atom Manager::joystick_type_name("Joystick");
const Atom Manager::keyboard_type_name("Keyboard");

Manager::Creator::Creator()
{
	if( queue || listeners )
		THROW(Gluck(__FUNCTION__, "queue or listeners already exist"));
	queue = new Queue;
	listeners = new Listeners;
}

Manager::Creator::~Creator()
{
	delete queue; queue = 0;
	delete listeners; listeners = 0;
}

void Manager::add_event(const Event & event)
{
	threads::Lock lock(mutex);
	queue->push( event );
}

void Manager::LifeCycle()
{
	bool was_event = true;
	Event ev;
	while(was_event)
	{
		{
			threads::Lock lock(mutex);
			if( !queue->empty() )
			{
				ev = queue->front();
				queue->pop();
			}
			else
				was_event = false;
		}

		if(was_event)
		{
			Listeners listenersCopy(*listeners);
			Listeners::const_iterator it = listenersCopy.begin();
			while(it != listenersCopy.end())
			{
				// validate listener
				bool is_valid = false;
				
				for(Listeners::const_iterator itr = listeners->begin(); itr != listeners->end(); ++itr)
				{
					if(*itr == *it)
					{
						is_valid = true;
						break;
					}
				}
				
				if(!is_valid)
				{
					// ivalid listener, next
					++it;
				}
				else
				{
					// send event
					(*it++)->on_input_event( ev );
				}
			}
		}
	}
}

void Manager::add_listener( Listener * listener )
{
	listeners->push_back( listener );
}

void Manager::remove_listener( Listener * listener )
{
	listeners->remove( listener );
}

Manager::AxisType Manager::get_axis_type( const std::string & hardware_name, const std::string & axis_name )
{
	hard::Hardware * ha = find_hardware( hardware_name );
	if( !ha )
		return NONE;
	return ha->get_axis_type( axis_name );
}

Atom Manager::get_hardware_type(const std::string & hardware_name)
{
	hard::Hardware * ha = find_hardware( hardware_name );
	if( !ha )
		return strange_type_name;
	return ha->get_type();
}

double Manager::get_axis_position( const std::string & hardware_name, const std::string & axis_name )
{
	hard::Hardware * ha = find_hardware( hardware_name );
	if( !ha )
		return 0;
	return ha->get_axis_position( axis_name );
}

hard::ForceEffect * Manager::create_force_effect( const std::string & hardware_name, const filesystem::String & effect_name )
{
	hard::Hardware * ha = find_hardware( hardware_name );
	if( !ha )
		return 0;
	return ha->create_force_effect( effect_name );
}

} // namespace input
} // namespace liba



